/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package service;

import com.openbrew.openbrewrf.Administration;
import com.openbrew.openbrewrf.HopContract;
import com.openbrew.openbrewrf.Hops;
import com.openbrew.openbrewrf.Malt;
import com.openbrew.openbrewrf.POLines;
import com.openbrew.openbrewrf.PurchaseOrder;
import com.openbrew.openbrewrf.SalesOrder;
import com.openbrew.openbrewrf.Supplies;
import com.openbrew.openbrewrf.Yeast;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import pdf.POPDFCreator;
import pdf.SOPDFCreator;
import service.enumerations.WarehouseIngredient;
import tools.HopContractTools;
import tools.InventoryModifiers;
import view.CreateSimplePurchaseOrderView;
import view.CreateSimpleSalesOrderView;
import view.SimplePurchaseOrderView;
import view.SimpleSalesOrderView;

/**
 *
 * @author chapmand
 */
@Stateless
@Path("com.openbrew.openbrewrf.purchaseorder")
public class PurchaseOrderFacadeREST extends AbstractFacade<PurchaseOrder> {
    @PersistenceContext(unitName = "com.openBrew_openBrewRF_war_1.0PU")
    private EntityManager em;

    public PurchaseOrderFacadeREST() {
        super(PurchaseOrder.class);
    }

    @POST
    @Override
    @WebMethod(operationName = "create")
    @Consumes({"application/xml", "application/json"})
    public PurchaseOrder create(@WebParam(name = "purchaseorder") PurchaseOrder entity) {
        entity = super.create(entity);
        PurchaseOrder po = find(entity.getPoid());
        if(po.getPOLinesCollection()!=null){
            final List<HopContract> hopContracts = getHopContracts(em);
            for(final POLines pol : po.getPOLinesCollection()){
                if(pol.getPolpn().getWhid().getWearhouseID() == WarehouseIngredient.HOPS.getDbId()){
                    if (pol.getPolpn() != null && checkForContract(pol.getPolpn().getTableID(), hopContracts, po)){
                        pol.setPOLContract(true);
                        em.merge(pol);
                    }
                }
            }
        }
        return po;
    }
    
    private List<HopContract> getHopContracts(final EntityManager en){
        TypedQuery<HopContract> query = en.createQuery(
                "SELECT h FROM HopContract h", HopContract.class);
        return query.getResultList();
    }
    
    private boolean checkForContract(final int hopID, final List<HopContract> hopContracts, final PurchaseOrder po){
        int year = po.getPODate().getYear();
        for(HopContract hc : hopContracts){
            if(hc.getHCHopID().getHid() == hopID){
                final int hcYear = hc.getHopContractYear().getYear();
                if(year >= hcYear){
                    if(hc.getContractLbsLeft()>0){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @PUT
    @Override
    @Consumes({"application/xml", "application/json"})
    public void edit(PurchaseOrder entity) {
        if(entity.getPOLinesCollection()!=null){
            performInventoryUpdates(entity.getPOLinesCollection());
        }
        super.edit(entity);
    }
    
    private void performInventoryUpdates(final List<POLines> poLines){
        for(final POLines entity : poLines){
            if(entity.getPolid()!=null && entity.getPolid()!=0){
                final int newQty = entity.getpOLQtyRcvd();
                POLines poLine = getPOLinesFromID(entity.getPolid(), em);
                if(poLine.getpOLQtyRcvd()!=newQty){
                    modifyInventory(entity, (newQty - poLine.getpOLQtyRcvd()));
                }
            }
        }
    }
    
    private void modifyInventory(final POLines entity, final int quantity) {
        final InventoryModifiers im = new InventoryModifiers();
        final int tid = entity.getPolpn().getTableID();
        final int whID = entity.getPolpn().getWhid().getWearhouseID();
        if(whID == WarehouseIngredient.HOPS.getDbId()){
            im.doReceiveHops(em, tid, quantity);
        } else if(whID == WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId()){
            im.doReceiveMalt(em, tid, quantity);
        } else if(whID != WarehouseIngredient.YEAST.getDbId()){
            im.doReceiveSupply(em, tid, quantity);
        }
    }
    
    private POLines getPOLinesFromID(final int id, final EntityManager en){
        TypedQuery<POLines> query = en.createQuery(
                    "SELECT p FROM POLines p WHERE p.polid = ?1", POLines.class);
        query.setParameter(1, id);
        final POLines poLine = query.getSingleResult();
        return poLine;
    }

    @PUT
    @Path("placePOOnOrder")
    @Consumes({"application/xml", "application/json"})
    public void placePOOnOrder(PurchaseOrder entity) {
        super.edit(entity);
        this.getEntityManager().getEntityManagerFactory().getCache().evictAll();
        final InventoryModifiers im = new InventoryModifiers();
        for(final POLines poLine : entity.getPOLinesCollection()){
            final int whID = poLine.getPolpn().getWhid().getWearhouseID();
            if(whID == WarehouseIngredient.HOPS.getDbId()){
                im.doUpdateHopsOnOrder(em, poLine.getPolpn().getTableID(), poLine.getPOLQty());
                if(poLine.getPOLContract()){
                    HopContractTools hct = new HopContractTools();
                    hct.updateContracts(em, poLine.getPOLQty(), poLine.getPolpn().getTableID(), entity);
                }
            } else if(whID == WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId()){
                im.doUpdateMaltOnOrder(em, poLine.getPolpn().getTableID(), poLine.getPOLQty());
            } else if(whID != WarehouseIngredient.YEAST.getDbId()){
                im.doUpdateSupplyOnOrder(em, poLine.getPolpn().getTableID(), poLine.getPOLQty());
            }
        }
    }

    @DELETE
    @Path("{id}")
    public void remove(@PathParam("id") Integer id) {
        super.remove(super.find(id));
    }

    @GET
    @Path("{id}")
    @Produces({"application/xml", "application/json"})
    public PurchaseOrder find(@PathParam("id") Integer id) {
        PurchaseOrder po = super.find(id);
        for(final POLines poLine : po.getPOLinesCollection()){
            final int whID = poLine.getPolpn().getWhid().getWearhouseID();
            final int tid = poLine.getPolpn().getTableID();
            if(whID == WarehouseIngredient.HOPS.getDbId()){
                final Hops hop = getHopFromID(tid);
                poLine.setDescription(hop.getHopName());
            } else if(whID == WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId()){
                final Malt malt = getMaltFromID(tid);
                poLine.setDescription(malt.getMaltName());
            } else if(whID == WarehouseIngredient.YEAST.getDbId()){
                final Yeast yeast = getYeastFromID(tid);
                poLine.setDescription(yeast.getYeastDesc());
            } else {
                final Supplies supply = getSupplyFromID(tid);
                poLine.setDescription(supply.getSupName());
            }
        }
        return po;
    }

    @GET
    @Override
    @Produces({"application/xml", "application/json"})
    public List<PurchaseOrder> findAll() {
        final List<PurchaseOrder> pos = super.findAll();
        for(final PurchaseOrder po : pos){
            for(final POLines poLine : po.getPOLinesCollection()){
                final int whID = poLine.getPolpn().getWhid().getWearhouseID();
                final int tid = poLine.getPolpn().getTableID();
                if(whID == WarehouseIngredient.HOPS.getDbId()){
                    final Hops hop = getHopFromID(tid);
                    poLine.setDescription(hop.getHopName());
                } else if(whID == WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId()){
                    final Malt malt = getMaltFromID(tid);
                    poLine.setDescription(malt.getMaltName());
                } else if(whID == WarehouseIngredient.YEAST.getDbId()){
                    final Yeast yeast = getYeastFromID(tid);
                    poLine.setDescription(yeast.getYeastDesc());
                } else {
                    final Supplies supply = getSupplyFromID(tid);
                    poLine.setDescription(supply.getSupName());
                }
            }
        }
        return pos;
    }
    
    private Hops getHopFromID(final int id){
        TypedQuery<Hops> query = em.createQuery(
                    "SELECT h FROM Hops h WHERE h.hid = ?1", Hops.class);
        query.setParameter(1, id);
        return query.getSingleResult();
    }
    
    private Malt getMaltFromID(final int id){
        TypedQuery<Malt> query = em.createQuery(
                    "SELECT m FROM Malt m WHERE m.maltID = ?1", Malt.class);
        query.setParameter(1, id);
        return query.getSingleResult();
    }
    
    private Yeast getYeastFromID(final int id){
        TypedQuery<Yeast> query = em.createQuery(
                    "SELECT y FROM Yeast y WHERE y.yid = ?1", Yeast.class);
        query.setParameter(1, id);
        return query.getSingleResult();
    }
    
    private Supplies getSupplyFromID(final int id){
        TypedQuery<Supplies> query = em.createQuery(
                    "SELECT s FROM Supplies s WHERE s.supID = ?1", Supplies.class);
        query.setParameter(1, id);
        return query.getSingleResult();
    }

    @GET
    @Path("{from}/{to}")
    @Produces({"application/xml", "application/json"})
    public List<PurchaseOrder> findRange(@PathParam("from") Integer from, @PathParam("to") Integer to) {
        return super.findRange(new int[]{from, to});
    }

    @GET
    @Path("findAllToVendor/{id}")
    @Produces({"application/xml", "application/json"})
    public List<PurchaseOrder> findAllToVendor(@PathParam("id") Integer id) {
        List<PurchaseOrder> pos = new ArrayList<PurchaseOrder>();
        for(final PurchaseOrder po : getFinishedPOS()){
            if(po.getPOLinesCollection()!=null){
                if(po.getPOLinesCollection().get(0).getPolpn().getStockVendID().getVid() == (int)id){
                    pos.add(po);
                }
            }
        }
        return pos;
    }
    
    private List<PurchaseOrder> getFinishedPOS(){
        TypedQuery<PurchaseOrder> query = em.createQuery(
                "SELECT p FROM PurchaseOrder p WHERE p.pOState = '30'", PurchaseOrder.class);
        return query.getResultList();
    }
    
    @GET
    @Path("runNamedQuery/{str}")
    @Override
    @Produces({"application/xml", "application/json"})
    public List<PurchaseOrder> runNamedQuery(@PathParam("str") String str){
        final List<PurchaseOrder> pos = super.runNamedQuery(str);
        for(final PurchaseOrder po : pos){
            for(final POLines poLine : po.getPOLinesCollection()){
                final int whID = poLine.getPolpn().getWhid().getWearhouseID();
                final int tid = poLine.getPolpn().getTableID();
                if(whID == WarehouseIngredient.HOPS.getDbId()){
                    final Hops hop = getHopFromID(tid);
                    poLine.setDescription(hop.getHopName());
                } else if(whID == WarehouseIngredient.MALT_AND_ADJUNCTS.getDbId()){
                    final Malt malt = getMaltFromID(tid);
                    poLine.setDescription(malt.getMaltName());
                } else if(whID == WarehouseIngredient.YEAST.getDbId()){
                    final Yeast yeast = getYeastFromID(tid);
                    poLine.setDescription(yeast.getYeastDesc());
                } else {
                    final Supplies supply = getSupplyFromID(tid);
                    poLine.setDescription(supply.getSupName());
                }
            }
        }
        return pos;
    }

    @GET
    @Path("{id}/po_pdf")
    @Produces({"application/pdf"})
    public StreamingOutput findHeaderImg(@PathParam("id") Integer id) {
        final PurchaseOrder po = super.find(id);
        return new StreamingOutput() {
            @Override
            public void write(OutputStream output) throws IOException, WebApplicationException {
                try {
                    final Administration admin = getAdmin(em);
                    final POPDFCreator popdf = new POPDFCreator();
                    CreateSimplePurchaseOrderView createView = new CreateSimplePurchaseOrderView();
                    final SimplePurchaseOrderView simplePurchaseOrderView = createView.GetSalesOrderString(po, em);

                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    popdf.createPDF(outputStream, po, simplePurchaseOrderView, admin);
                    byte[] bytes = outputStream.toByteArray();
                    output.write(bytes);
                } catch (IOException e) {
                    throw new WebApplicationException(e);
                }
            }
        };
    }
    
    /***************************************************************************
     * Database modification functions.
     **************************************************************************/
    private Administration getAdmin(final EntityManager en){
        TypedQuery<Administration> query = en.createQuery(
            "SELECT a FROM Administration a WHERE a.aNum = '1'", Administration.class);
        Administration admin = query.getSingleResult();
        return admin;
    }

    @GET
    @Path("count")
    @Produces("text/plain")
    public String countREST() {
        return String.valueOf(super.count());
    }

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }
    
}
